/*
 * Copyright (C) 2011-2013 Eric Lasota
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef __RDX_BASICTYPES_HPP__
#define __RDX_BASICTYPES_HPP__

//#pragma warning(error:4183)

#include <stdlib.h>

#include "rdx_platform.hpp"
#include "rdx_pragmas.hpp"

#define RDX_OFFSETOF(t, f)	(\
	static_cast<RDX::LargeInt>(\
		reinterpret_cast<const char *>( &reinterpret_cast<const t *>(NULL)->f ) - \
		reinterpret_cast<const char *>(NULL)\
	)\
)

#define RDX_ALIGNOF(t)	( RDX_OFFSETOF( RDX::AlignmentCheck<t>, v) )


namespace RDX
{
	template<class _T>
	struct AlignmentCheck
	{
		char pad;
		_T v;
	};

	typedef RDX_CHAR_TYPE		Char;
	typedef RDX_INT_TYPE		Int;							// Needs to be no larger than LargeInt
	typedef RDX_UINT_TYPE		UInt;							// Needs to be no larger than LargeInt
	typedef RDX_FLOAT_TYPE		Float;
	typedef RDX_UINT8_TYPE		Byte;
	typedef RDX_SINT16_TYPE		Short;
	typedef RDX_UINT16_TYPE		UShort;
	typedef RDX_FLOAT64_TYPE	Double;
	typedef RDX_UINT32_TYPE		HashValue;
	typedef RDX_SINT64_TYPE		Long;
	typedef RDX_BOOL_TYPE		Bool;

	typedef RDX_LARGEINT_TYPE	LargeInt;						// Needs to be the same size as a pointer
	typedef RDX_LARGEUINT_TYPE	LargeUInt;						// Needs to be the same size as a pointer
	typedef RDX_SINT64_TYPE		Int64;
	typedef	RDX_UINT64_TYPE		UInt64;
	typedef RDX_SINT32_TYPE		Int32;
	typedef RDX_SINT16_TYPE		Int16;
	typedef RDX_SINT8_TYPE		Int8;
	typedef RDX_UINT32_TYPE		UInt32;
	typedef RDX_UINT16_TYPE		UInt16;
	typedef RDX_UINT8_TYPE		UInt8;
	typedef RDX_FLOAT64_TYPE	Float64;
	typedef RDX_FLOAT32_TYPE	Float32;

#ifdef RDX_ENABLE_LARGEINT_BULK_SERIALIZE
	typedef RDX_LARGEINT_TYPE	BinPackageLargeInt;
#else
	typedef RDX_BINARY_STORAGE_INT_TYPE	BinPackageLargeInt;
#endif

	typedef RDX_HUGEINT_TYPE	HugeInt;
	typedef RDX_HUGEUINT_TYPE	HugeUInt;

	RDX_ATOMICINT_DEF;
	typedef RDX_ATOMICINT_NV_TYPE	NonAtomicInt;

#ifdef RDX_ENABLE_SMP
#	define RDX_POSSIBLY_VOLATILE	volatile
	typedef volatile AtomicInt	PossiblyAtomicInt;
#else
#	define RDX_POSSIBLY_VOLATILE
	typedef NonAtomicInt	PossiblyAtomicInt;
#endif

	static const Bool TrueValue = true;
	static const Bool FalseValue = false;

	static const Char CHAR_Invalid = static_cast<Char>(-1);

	class EnumValue
	{
	public:
		typedef RDX_ENUM_TYPE UnderlyingType;
	protected:
		UnderlyingType _value;
	public:
		bool operator !=(const EnumValue &rs) const;
		bool operator ==(const EnumValue &rs) const;
		bool operator >=(const EnumValue &rs) const;
		bool operator <=(const EnumValue &rs) const;
		bool operator >(const EnumValue &rs) const;
		bool operator <(const EnumValue &rs) const;

		static EnumValue From(UnderlyingType v);
		UnderlyingType Value() const;
	};

	static const LargeInt ALIGN_LargeInt			= RDX_ALIGNOF(LargeInt);
	static const LargeInt ALIGN_Bool				= RDX_ALIGNOF(Bool);
	static const LargeInt ALIGN_HashValue			= RDX_ALIGNOF(HashValue);
	static const LargeInt ALIGN_Float				= RDX_ALIGNOF(Float);
	static const LargeInt ALIGN_Int					= RDX_ALIGNOF(Int);
	static const LargeInt ALIGN_Char				= RDX_ALIGNOF(Char);
	static const LargeInt ALIGN_Short				= RDX_ALIGNOF(Short);
	static const LargeInt ALIGN_Byte				= RDX_ALIGNOF(Byte);

	namespace ObjectManagement
	{
		typedef UInt8 ScanID;
	}

	namespace Programmability
	{

		struct Method;
		struct Exception;
		struct Type;

		// WARNING: ILOP_move bulk copies are sensitive to the property order here, as is ILOP_obj_tovarying
		template<class _T>
		struct RuntimePointer
		{
			void	*objectRef;
			_T		*valueRef;
			
			static inline RuntimePointer<_T> From(void *obj, _T *ptr)
			{
				RuntimePointer<_T> rp;
				rp.objectRef = obj;
				rp.valueRef = ptr;
				return rp;
			}

			static inline RuntimePointer<_T> From(_T *ptr)
			{
				return RuntimePointer<_T>::From(NULL, ptr);
			}

			static inline RuntimePointer<_T> From(const _T *ptr)
			{
				return RuntimePointer<_T>::From(NULL, const_cast<_T*>(ptr));
			}

			static inline RuntimePointer<_T> From(void *obj, const _T *ptr)
			{
				return RuntimePointer<_T>::From(obj, const_cast<_T*>(ptr));
			}

			template<class _otherT>
			inline RuntimePointer<_otherT> StaticCast() const
			{
				RuntimePointer<_otherT> v;
				v.objectRef = this->objectRef;
				v.valueRef = static_cast<_otherT*>(this->valueRef);
				return v;
			}

			template<class _otherT>
			inline RuntimePointer<_otherT> ReinterpretCast() const
			{
				RuntimePointer<_otherT> v;
				v.objectRef = this->objectRef;
				v.valueRef = reinterpret_cast<_otherT*>(this->valueRef);
				return v;
			}
		};

		struct TypedRuntimePointer
		{
			RuntimePointer<void>					rtp;
			const RDX::Programmability::Type		*type;
		};

		union RuntimeStackValue
		{
			void *asObjectRef;
			RuntimePointer<void> asRTP;
			Double asDouble;
			LargeInt asLargeInt;
			EnumValue asEnumValue;
			Short asShort;
			Char asChar;
			Byte asByte;
			Int asInt;
			Long asLong;
		};
		
		static const LargeInt ALIGN_RuntimeStackValue	= RDX_ALIGNOF(RuntimeStackValue);
		static const LargeInt ALIGN_EnumValue			= RDX_ALIGNOF(EnumValue);
		static const LargeInt ALIGN_RuntimePointer		= RDX_ALIGNOF(RuntimePointer<void>);
		static const LargeInt ALIGN_TypedRuntimePointer	= RDX_ALIGNOF(TypedRuntimePointer);
	}
}

inline bool RDX::EnumValue::operator !=(const RDX::EnumValue &rs) const
{
	return this->_value != rs._value;
}

inline bool RDX::EnumValue::operator ==(const RDX::EnumValue &rs) const
{
	return this->_value == rs._value;
}

inline bool RDX::EnumValue::operator >=(const RDX::EnumValue &rs) const
{
	return this->_value >= rs._value;
}

inline bool RDX::EnumValue::operator <=(const RDX::EnumValue &rs) const
{
	return this->_value <= rs._value;
}

inline bool RDX::EnumValue::operator >(const RDX::EnumValue &rs) const
{
	return this->_value > rs._value;
}

inline bool RDX::EnumValue::operator <(const RDX::EnumValue &rs) const
{
	return this->_value < rs._value;
}

inline RDX::EnumValue RDX::EnumValue::From(RDX::EnumValue::UnderlyingType v)
{
	RDX::EnumValue ev;
	ev._value = v;
	return ev;
}

inline RDX::EnumValue::UnderlyingType RDX::EnumValue::Value() const
{
	return _value;
}

#endif
